package com.sqllog.admin.sql.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageInfo;
import com.sqllog.admin.sql.domain.QueryParamInfo;
import com.sqllog.admin.sql.domain.SqlChangeEntity;
import com.sqllog.admin.sql.domain.SqlEntity;
import com.sqllog.admin.sql.domain.SqlLogInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * TODO
 *
 * @author chennengcheng
 * @date 2022-01-14 11:05
 * @remark
 */

@Service
public class CanalServerLogService {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 分页查询sql 明细记录
     *
     * @return
     */
    public PageInfo<SqlLogInfo> findPage(QueryParamInfo queryParamInfo) {
        if (StringUtils.isBlank(queryParamInfo.getCollectionName())) {
            return new PageInfo<>();
        }

        Query query = getSqlLogQuery(queryParamInfo);
        Query countQuery = getSqlLogQueryCount(queryParamInfo);
        // 结果列表
        List<SqlLogInfo> sqlLogVos = mongoTemplate.find(query, SqlLogInfo.class, queryParamInfo.getCollectionName());
        long totalCount = mongoTemplate.count(countQuery, SqlLogInfo.class, queryParamInfo.getCollectionName());
        PageInfo<SqlLogInfo> pageResult = new PageInfo<>();
        for (SqlLogInfo sqlLogVo : sqlLogVos) {
            // 因为数据时区取错了，所以需要往后推 8 小时
            DateTime dateTime = DateUtil.offsetHour(sqlLogVo.getCreateDate(), 8);
            sqlLogVo.setCreateDate(dateTime.toJdkDate());
            sqlLogVo.setCollectionName(queryParamInfo.getCollectionName());
        }

        pageResult.setList(sqlLogVos);
        pageResult.setTotal(totalCount);
        pageResult.setPageNum(queryParamInfo.getPage());
        pageResult.setPageSize(queryParamInfo.getLimit());
        return pageResult;
    }

    public SqlChangeEntity getById(String id, String collectionName) {
        // 先查出当前记录
        SqlLogInfo sqlLogEntityOld = mongoTemplate.findById(id, SqlLogInfo.class, collectionName);
        String[] split = collectionName.split("\\.");
        SqlChangeEntity sqlChangeEntity = new SqlChangeEntity();
        sqlChangeEntity.setDataBaseName(split[0]);
        sqlChangeEntity.setTableName(split[1]);
        if (Objects.isNull(sqlLogEntityOld)) {
            return sqlChangeEntity;
        }

        Map<String, String> updateDataMap1 = JSONUtil.toBean(sqlLogEntityOld.getDataMapOfJson(), HashMap.class);
        if (CollectionUtil.isEmpty(updateDataMap1)) {
            sqlChangeEntity.setSqlEntities(new ArrayList<>());
            return sqlChangeEntity;
        }

        String rowIdValue = sqlLogEntityOld.getRowIdValue();
        long createDate = sqlLogEntityOld.getCreatTime();
        // 再查出当前记录之前的记录
        Query queryOlds = new Query();
        queryOlds.addCriteria(Criteria.where("rowIdValue").is(rowIdValue));
        queryOlds.addCriteria(Criteria.where("creatTime").lt(createDate));
        queryOlds.with(Sort.by(Sort.Direction.DESC, "creatTime"));
        queryOlds.limit(1);
        SqlLogInfo sqlLogHistory = getPreviousHistory(queryOlds, collectionName);
        List<SqlEntity> sqlEntities = new ArrayList<>();
        for (Map.Entry<String, String> entry : updateDataMap1.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            SqlEntity sqlEntity = new SqlEntity();
            sqlEntity.setField(key);
            sqlEntity.setNewValue(value);
            if (Objects.isNull(sqlLogHistory)) {
                sqlEntities.add(sqlEntity);
                continue;
            }

            Map<String, String> updateDataMap = JSONUtil.toBean(sqlLogHistory.getDataMapOfJson(), Map.class);
            for (Map.Entry<String, String> entryValue : updateDataMap.entrySet()) {
                String keyValue = entryValue.getKey();
                String valueValue = entryValue.getValue();
                if (key.equals(keyValue)) {
                    sqlEntity.setOldValue(valueValue);
                    break;
                }
            }

            sqlEntities.add(sqlEntity);
        }


        sqlChangeEntity.setSqlEntities(sqlEntities);
        return sqlChangeEntity;
    }

    /**
     * 获取上一个月的名字
     *
     * @param collectionName
     * @return
     */
    public String getPreviousMonthName(String collectionName) {
        String[] values = collectionName.split("\\.");
        String dateStr = values[values.length - 1];
        DateTime parse = DateUtil.parse(dateStr, "yyyy-MM");
        DateTime dateTime = DateUtil.offsetMonth(parse, -1);
        String oldCollection = DateUtil.format(dateTime, "yyyy-MM");
        return collectionName.replace(dateStr, oldCollection);
    }

    public SqlLogInfo getPreviousHistory(Query queryOlds, String collectionName) {
        if (mongoTemplate.collectionExists(collectionName)) {
            SqlLogInfo sqlLogHistory = mongoTemplate.findOne(queryOlds, SqlLogInfo.class, collectionName);
            if (Objects.isNull(sqlLogHistory)) {
                collectionName = getPreviousMonthName(collectionName);
                return getPreviousHistory(queryOlds, collectionName);
            } else {
                return sqlLogHistory;
            }
        } else {
            return null;
        }
    }

    /**
     * sqlLog 查询
     *
     * @param sqlLogDto
     * @return
     */
    private Query getSqlLogQuery(QueryParamInfo sqlLogDto) {
        Query query = new Query();
        if (StrUtil.isNotBlank(sqlLogDto.getSql())) {
            query.addCriteria(Criteria.where("dataMapOfJson").regex(".*?" + sqlLogDto.getSql() + ".*"));
        }

        if (StrUtil.isNotBlank(sqlLogDto.getObjType())) {
            query.addCriteria(Criteria.where("objType").is(sqlLogDto.getObjType().toLowerCase()));
        }

        if (StrUtil.isNotBlank(sqlLogDto.getType())) {
            query.addCriteria(Criteria.where("type").is(sqlLogDto.getType().toLowerCase()));
        }

        if (StrUtil.isNotBlank(sqlLogDto.getId())) {
            query.addCriteria(Criteria.where("rowIdValue").is(sqlLogDto.getId()));
        }
        query.with(Sort.by(Sort.Direction.valueOf(sqlLogDto.getOrder()), sqlLogDto.getSort()));
        query.skip((sqlLogDto.getPage() - 1) * sqlLogDto.getLimit()).limit(sqlLogDto.getLimit());
        return query;
    }

    /**
     * sqlLog 查询
     *
     * @return
     */
    private Query getSqlLogQueryCount(QueryParamInfo queryParamInfo) {
        Query query = new Query();
        if (StrUtil.isNotBlank(queryParamInfo.getSql())) {
            query.addCriteria(Criteria.where("dataMapOfJson").regex(".*?" + queryParamInfo.getSql() + ".*"));
        }

        if (StrUtil.isNotBlank(queryParamInfo.getObjType())) {
            query.addCriteria(Criteria.where("objType").is(queryParamInfo.getObjType().toLowerCase()));
        }

        if (StrUtil.isNotBlank(queryParamInfo.getType())) {
            query.addCriteria(Criteria.where("type").is(queryParamInfo.getType().toLowerCase()));
        }

        if (StrUtil.isNotBlank(queryParamInfo.getId())) {
            query.addCriteria(Criteria.where("rowIdValue").is(queryParamInfo.getId()));
        }
        return query;
    }
}
